using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ContentOverContainer.Common.Converter;
using ContentOverContainer.Converter;
using ContentOverContainer.Converter.Converter;
using Roslyn.Compilers.CSharp;
using Roslyn.Compilers.Common;
using ContentOverContainer;

namespace ContentOverContainer.Common.Converter
{
    /// <summary>
    /// Helper class for cnverting varios expression syntaxes.
    /// </summary>
    /// <author>Harald Binkle</author>
    public static class ExpressionSyntaxConverter
    {
        public static ChangeNodeInfo Convert(this ExpressionSyntax pExprSyntax, ConverterContext pConverterData)
        {
            var exprSyntax = pExprSyntax;
            if (exprSyntax is BinaryExpressionSyntax)
            {
                SyntaxKind kind = exprSyntax.Kind;
                if (kind == SyntaxKind.AssignExpression)
                    return AssignmentConverter.ConvertAssignExpression((BinaryExpressionSyntax)exprSyntax, pConverterData);
                if (kind == SyntaxKind.AddAssignExpression)
                    return AddAssignConverter.ConvertAddAssignExpression((BinaryExpressionSyntax)exprSyntax, pConverterData);
                if (kind == SyntaxKind.SubtractAssignExpression)
                    return SubtractAssignConverter.ConvertSubtractAssignExpression((BinaryExpressionSyntax)exprSyntax, pConverterData);
                if (kind == SyntaxKind.EqualsExpression)
                    return EqualsConverter.ConvertEqualsExpression((BinaryExpressionSyntax)exprSyntax, pConverterData);
                if (kind == SyntaxKind.BitwiseOrExpression)
                    return MultConverter.ConvertMultExpression((BinaryExpressionSyntax)exprSyntax, pConverterData);
                if (kind == SyntaxKind.ExclusiveOrExpression)
                    return CollConverter.ConvertCollExpression((BinaryExpressionSyntax)exprSyntax, pConverterData);
            }
            
            if (exprSyntax is ConditionalExpressionSyntax)
                return ConditionalExpressionConverter.ConvertConditionalExpression((ConditionalExpressionSyntax)exprSyntax, pConverterData);

            if (exprSyntax is MemberAccessExpressionSyntax)
                return MemberAccessAndInvocationconverter.ConvertMemberAccessExpression((MemberAccessExpressionSyntax)exprSyntax, pConverterData);

            if (exprSyntax is CastExpressionSyntax)
                return CastConverter.ConvertCastExpression((CastExpressionSyntax)exprSyntax, pConverterData);        

            return new ChangeNodeInfo(pExprSyntax);
        }

        public static List<ParameterPair> ResolveArgumentListTypes(this MethodDeclarationSyntax pMethodDeclaration)
        {
            var result = new List<ParameterPair>();

            var param = pMethodDeclaration.ParameterList.Parameters;
            foreach (var parameterSyntax in param)
            {
                result.Add(new ParameterPair() { Type = parameterSyntax.Type, Name = Syntax.ParseName(parameterSyntax.Identifier.ToString()) });
            }

            return result;
        }

        public static bool GatherBinaryExpressionInfo(ConverterContext pConverterData, ExpressionSyntax value, ExpressionSyntax member, out List<ParameterPair> parameter)
        {
            bool valueIsAnyAnnotated = false;
            TypeSyntax valueType = null;
            var objCreationSyntax = value as ObjectCreationExpressionSyntax;
            if (objCreationSyntax == null) //not a new object
            {
                var valueName = value.FirstAncestorOrSelf<SimpleNameSyntax>();
                if (valueName != null)
                {
                    var valueDecl = valueName.GetMemberDeclaration(pConverterData.SemanticModel);
                    if (valueDecl == null) //case of properties we are getting null "value"
                    {
                        if (valueName.ToString().Equals("value", StringComparison.OrdinalIgnoreCase))
                        {
                            valueDecl = value.FirstAncestorOrSelf<PropertyDeclarationSyntax>();
                        }
                    }
                    if (valueDecl != null)
                    {
                        valueIsAnyAnnotated = valueDecl.GetMultiplicityKind() == MultiplicityKind.Any;
                        valueType = valueDecl.GetDeclarationType();
                        if (valueIsAnyAnnotated)
                            valueType = valueDecl.GetMultiplicityAttributes()
                                                 .GetMultiplicityType(valueType, MultiplicityKind.Any);
                    }
                }
            }

            //vaule and member type must be assignable, so we can use member type which is easier in case of properties where getting the type of "value" would be a special case
            var memberName = member.FirstAncestorOrSelf<SimpleNameSyntax>();
            var nameDecl = memberName.GetMemberDeclaration(pConverterData.SemanticModel);

            var memberType = nameDecl.GetDeclarationType();
            if (valueType == null)
                valueType = memberType;

            parameter = new List<ParameterPair>();
            if (objCreationSyntax == null)
                parameter.Add(new ParameterPair() { Type = valueType, Name = value });
            //no parameter needed for ObjectCreationExpressionSyntax
            return valueIsAnyAnnotated;
        }
    }

    
}
